package main

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha1"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"math/big"
	"os"
)

func ECCGen() {
	//使用ecd生成秘钥对，1使用模型,2随机数
	privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
	if err != nil {
		panic(err)
	}
	//将私钥写入磁盘
	//x509序列化
	derText, err := x509.MarshalECPrivateKey(privateKey)
	if err != nil {
		panic(err)
	}
	block := pem.Block{
		Type:  "Ecdsa private key",
		Bytes: derText,
	}
	file, err := os.Create("ecaprivate.pem")
	if err != nil {
		panic(err)
	}
	err = pem.Encode(file, &block)
	if err != nil {
		panic(err)
	}
	file.Close()
	//将公钥写入磁盘
	//从私钥中得到公钥
	public := privateKey.PublicKey
	//	使用x509进行序列化
	derText, err = x509.MarshalPKIXPublicKey(&public)
	if err != nil {
		panic(err)
	}
	block = pem.Block{
		Type:  "Ecdsa public key",
		Bytes: derText,
	}
	file, err = os.Create("ecapublic.pem")
	if err != nil {
		panic(err)
	}
	pem.Encode(file, &block)
	file.Close()
	return
}
func EccSign(sourceData []byte, privateKeyFilePath string) ([]byte, []byte) {
	//1、打开私钥文件，读出内容
	file, err := os.Open(privateKeyFilePath)
	if err != nil {
		panic(err)
	}
	info, err := file.Stat()
	buf := make([]byte, info.Size())
	file.Read(buf)
	//2、pem解密
	block, _ := pem.Decode(buf)
	//x509解密
	privateKey, err := x509.ParseECPrivateKey(block.Bytes)
	if err != nil {
		panic(err)
	}
	//哈希运算
	hashText := sha1.Sum(sourceData)
	//数字签名
	r, s, err := ecdsa.Sign(rand.Reader, privateKey, hashText[:])
	if err != nil {
		panic(err)
	}
	rText, err := r.MarshalText()
	if err != nil {
		panic(err)
	}
	sText, err := s.MarshalText()
	if err != nil {
		panic(err)
	}
	defer file.Close()
	return rText, sText

}

func EccVerify(rText, sText, sourceData []byte, publicKeyfilePath string) bool {
	//读取公钥文件
	file, err := os.Open(publicKeyfilePath)
	if err != nil {
		panic(err)
	}
	info, err := file.Stat()
	if err != nil {
		panic(err)
	}
	buf := make([]byte, info.Size())
	file.Read(buf)
	//pem编码
	block, _ := pem.Decode(buf)
	piblicStream, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		panic(err)
	}
	//接口转换公钥
	publicKey := piblicStream.(*ecdsa.PublicKey)
	hashText := sha1.Sum(sourceData)
	var r, s big.Int
	r.UnmarshalText(rText)
	s.UnmarshalText(sText)
	//认证
	res := ecdsa.Verify(publicKey, hashText[:], &r, &s)
	defer file.Close()
	return res
}

func main() {
	data := []byte("Process finished with exit code 0")
	data2 := []byte("Process finished with exit code 1")
	ECCGen()
	r, s := EccSign(data, "ecaprivate.pem")
	torf := EccVerify(r, s, data2, "ecapublic.pem")
	fmt.Println(torf)
}
